package nl.foldervisualizer.business
{
	import com.ericfeminella.collections.HashMap;
	import com.ericfeminella.collections.IMap;
	
	import flash.filesystem.File;
	
	import mx.collections.ArrayCollection;
	import mx.collections.Sort;
	import mx.collections.SortField;
	
	import nl.foldervisualizer.model.Constants;
	
	public final class FolderVisualizer
	{
		public var folderSizes:IMap
		public var parent:String
		
		public function init(folder:File):void {
			this.parent = folder.nativePath
			if (StringUtils.endsWith(this.parent, File.separator)) {
				this.parent = this.parent.substring(0, this.parent.length - 1)
			}
			
			this.folderSizes = FileUtils.addFilesRecurse(folder)
		}
		
		private function computeSize(map:IMap, directory:String, aggregates:IMap):void {
			var size:Number = aggregates.getValue(directory)
			if (isNaN(size)) size = 0
			size += map.getValue(directory)
			aggregates.put(directory, size)	
		}
		
		/**
		 * Removes the specified folder from the folderSizes Map.
		 * This function can be used for example when the specified folder is deleted.
		 */
		public function removeFromFolderSizes(folder:File):void {
			var path:String = folder.nativePath
			var sizeOfSelected:Number = folderSizes.getValue(path)
			var parentOfSelected:String = path.substring(0, path.lastIndexOf(File.separator))
			var keySet:Array = folderSizes.getKeys()
			for each (var key:String in keySet) {
				if (StringUtils.startsWith(key, path)) {
					folderSizes.remove(key)
				}
			}
			var newSizeOfParent:Number = folderSizes.getValue(parentOfSelected) - sizeOfSelected
			if (newSizeOfParent == 0) {
				newSizeOfParent = 1
			}
			folderSizes.put(parentOfSelected, newSizeOfParent)
		}

		public function visualize(folder:File, ceiling:int = 10):ArrayCollection {
			var toVisualize:IMap = new HashMap()
			var parent:String = folder.nativePath
			
			var files:Array = folder.getDirectoryListing()
			var totalSize:Number = 0
			for each (var file:File in files) {
				if (file.isDirectory) {
					var path:String = file.nativePath
					toVisualize.put(path, this.folderSizes.getValue(path))
					totalSize += this.folderSizes.getValue(path)
				} else {
					toVisualize.put(file.nativePath, file.size)
					totalSize += file.size
				}	               	
			}
						
			var data:ArrayCollection = new ArrayCollection()
			var keySet:Array = toVisualize.getKeys()
			for each (var key:String in keySet) {
				data.addItem(new FolderItem(key, (toVisualize.getValue(key) / totalSize) * 100, toVisualize.getValue(key)))
			}

			sortFolderItems(data)
			aggregateSmallestEntries(data, ceiling)
			
			return data
		}
		
		private static function sortFolderItems(data:ArrayCollection):void {
			var sortItem:Sort = new Sort()
			
			var sortByRelativeSize:SortField = new SortField("relativeSize", false, true)
			sortItem.fields = [sortByRelativeSize]
						
			data.sort = sortItem
			data.refresh()
		}
		
		private static function aggregateSmallestEntries(data:ArrayCollection, ceiling:int):void {
			var aggregates:FolderItem = new FolderItem(Constants.OTHER)
			var limit:int = data.length - ceiling
			
			for (var i:int = 0; i <= limit; i++) {
				aggregates = aggregates.add(data.getItemAt(data.length - 1) as FolderItem)
				data.removeItemAt(data.length - 1)
			}					
			
			if (ceiling > 0) {
				data.addItem(aggregates)
			}
		}
	}
}